package com.zerro.litez.runtime;


import com.google.gson.Gson;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

public abstract class LitEzDao<T> {

    protected LitEzSupporter supporter;
    protected EntityFormatter<T> formatter;


    protected T[] resultSetToEntityArray(ResultSet resultSet, T[] arr) {

        int i = 0;
        try {
            if (resultSet != null && resultSet.first()) {
                do {
                    arr[i] = formatter.resultSetToEntity(resultSet, supporter);
                    i++;
                } while (resultSet.next());
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return arr;
    }

    List<T> mergedEntities = new ArrayList<>();

    protected final void startMergeEntities() {
        mergedEntities = null;
    }

    @SafeVarargs
    protected final void addMergeEntity(T... entity) {
        mergedEntities.addAll(Arrays.asList(entity));
    }

    protected T[] getMergedEntities() {
        return (T[]) mergedEntities.toArray();
    }

    protected final ResultSet doInsert(String insert, T entity) throws SQLException {
        PreparedStatement stmt = supporter.getStmt(insert + formatter.valuesOf(entity), true);
        stmt.executeUpdate();
        return stmt.getGeneratedKeys();

    }

    /**
     * 更新大量数据，聚合的sql
     */
    protected final String getLongUpdateSql(T[] entities, String tableName) {
        StringBuilder sql = new StringBuilder("update " + tableName + " set ");
        for (int i = 0; i < formatter.getColumnCount(); i++) {
            if (i == formatter.getAutoIncIndex()){
                continue;
            }
            String columnName = formatter.getNameOf(i);
            StringBuilder cases = new StringBuilder()
                    .append(columnName).append(" = ")
                    .append("case");
            for (T entity : entities) {
                String when = formatter.getPrimaryKeyValue(entity);
                cases.append(" when ").append(when)
                        .append(" then ").append(formatter.getValueOrDefaultOf(entity, i));
            }
            cases.append(" else ").append(columnName).append(" end");
            if (i < formatter.getColumnCount() - 1) {
                cases.append(",");
            }
            cases.append("\n");
            sql.append(cases);
        }
        sql.append(" where ")
                .append(formatter.getPrimaryKeyValues(entities));
        return sql.toString();
    }

    protected final String getSingleUpdateSql(T entity, String tableName) {
        StringBuilder stmt = new StringBuilder("update " + tableName);
        StringBuilder sets = new StringBuilder(" set ");
        for (int i = 0; i < formatter.getColumnCount(); i++) {
            sets.append(formatter.getNameOf(i))
                    .append(" = ")
                    .append(formatter.getValueOrDefaultOf(entity, i));
            if (i < formatter.getColumnCount() - 1) {
                sets.append(",");
            }
        }

        stmt.append(sets)
                .append(" where ")
                .append(formatter.getPrimaryKeyValue(entity));
        return stmt.toString();
    }

    @SafeVarargs
    protected final int doUpdate(String tableName, T... data) throws SQLException {
        String sql = "";
        if (data.length == 1) {
            for (T t : data) {
                sql = getSingleUpdateSql(t, tableName);
                break;
            }
        } else {
            sql = getLongUpdateSql(data, tableName);
        }
        return doUpdateDelete(sql);
    }

    protected final int doUpdate(String tableName, Collection<T> data) throws SQLException {
        String sql = "";
        if (data.size() == 1) {
            for (T t : data) {
                sql = getSingleUpdateSql(t, tableName);
                break;
            }
        } else {
            sql = getLongUpdateSql((T[]) data.toArray(), tableName);
        }
        return doUpdateDelete(sql);
    }

    protected final int doUpdateDelete(String sql) throws SQLException {
        System.out.println(sql);
        return supporter.getStmt(sql, false).executeUpdate();
    }

    protected interface Getter<E>{
        Object getPrimaryKey(E entity);
    }

    protected final <E> String getPrimaryKeys(E[] entities, Getter<E> getter) {
        StringBuilder values = new StringBuilder();
        for (int i = 0; i < entities.length; i++) {
            E entity = entities[i];
            values.append(getter.getPrimaryKey(entity));
            if (i < entities.length - 1) {
                values.append(",");
            }
        }
        return values.toString();
    }

    /**
     * 将字符串中的 ' 转义为 \'
     */
    protected String escape(String str){
        if (str == null) {
            return "";
        }
        return str.replace("'", "\\'");
    }

    Gson gson = new Gson();
    protected String escape(Collection<?> data){
        String json = gson.toJson(data);
        return escape(json.substring(1, json.length() - 1));
    }


    /**
     * @return Dao的全限定名
     */
    public abstract String __$$__getName();

    public void __$$__setSupporter(LitEzSupporter supporter) {
        this.supporter = supporter;
    }

    public void __$$__setFormatter(EntityFormatter<T> formatter) {
        this.formatter = formatter;
    }
}
